#include <my_header.h>
// pthread_cond_broadcast 是以**广播的方式**把指定条件变量的阻塞队列线程**全部唤醒**.
#if 0
主线程创建两个子线程都指向入口函数func 开始执行，主线程
首先睡5s，子线程1开始执行，打印1child，beforechild，之后被阻塞
子线程2开始执行，遇到和子线程1一样的情况，主线程5s结束
开始唤醒，此时使用的是broadcast全部唤醒，将执行1after，
2after，两个子线程全部执行，若换成signal只会唤醒1个
子线程2被阻塞，只能通过2好信号结束主进程，以结束子线程2.
#endif
/* Usage:  ./24_pthread_cond_broadcast*/
typedef struct share_value{
    int num;
    pthread_mutex_t lock;
    pthread_cond_t cond;
}share_value_t;
void *func(void *arg)
{
    share_value_t *pshareValue = (share_value_t *)arg;

    // 加锁和解锁
    pthread_mutex_lock(&pshareValue->lock);
    pshareValue->num++;
    int childNum = pshareValue->num;
    pthread_mutex_unlock(&pshareValue->lock);

    sleep(childNum);
    printf(" I am  %d child thread \n", childNum);

    // 加锁和解锁
    pthread_mutex_lock(&pshareValue->lock);
    printf(" I am  %d child thread before\n", childNum);
    pthread_cond_wait(&pshareValue->cond, &pshareValue->lock);
    printf("I am %d child thread after \n",childNum);
    pthread_mutex_unlock(&pshareValue->lock);


    return NULL;
}
int main(void){                        
    // 声明结构体对象，并初始化结构体的成员
    share_value_t shareValue;
    shareValue.num = 0;
    pthread_mutex_init(&shareValue.lock, NULL);
    pthread_cond_init(&shareValue.cond, NULL);

    pthread_t tid1, tid2;
    int ret_create1 = pthread_create(&tid1, NULL, func, &shareValue);
    THREAD_ERROR_CHECK(ret_create1, "pthread_create1");
    int ret_create2 = pthread_create(&tid2, NULL, func, &shareValue);
    THREAD_ERROR_CHECK(ret_create2, "pthread_create2");

    sleep(5);
    pthread_mutex_lock(&shareValue.lock);
    // 唤醒多个线程的阻塞
    pthread_cond_broadcast(&shareValue.cond);
    // 唤醒一个线程的阻塞
    // pthread_cond_signal(&shareValue.cond);
    pthread_mutex_unlock(&shareValue.lock);

    // 捕获线程并清理资源
    int ret_join1 = pthread_join(tid1, NULL);
    THREAD_ERROR_CHECK(ret_join1, "pthread_join1");
    int ret_join2 = pthread_join(tid2, NULL);
    THREAD_ERROR_CHECK(ret_join2, "pthread_join2");

    // 销毁条件变量和锁
    pthread_mutex_destroy(&shareValue.lock);
    pthread_cond_destroy(&shareValue.cond);
    return 0;
}

#if 0
// 虚假唤醒: pthread_cond_broadcast 唤醒了多个线程, 每一个进程一定会立即获得锁? 不会
eg: 广播: 唤醒了5个线程, 5个线程使用的还是同一把锁, 这个醒的5个线程, 都要去试图获取那个锁, 1个成功, 4个等待锁
1个成功获得锁的线程做了针对性的事情, 导致条件变化了; 也就是说, 其余线程被喊醒了, 在从唤醒到拿到锁的这个时间, 别的线程对共享数据做了操作, 导致某些线程拿到锁的时候, 已经不满足最开始的被唤醒条件,  做不了事, 即虚假唤醒.
而解决虚假唤醒的一种良好的方式, 就是让wait配合while循环使用, 当取得锁的时候, 再对最开始的条件重新进行一次检测.
while(num >= 5){
    重新wait;
}
#endif
